#include "dtu_memory.h"
#include "dtu_log.h"

/* 全局内存管理器 */
static memory_manager_t g_memory_manager = {0};

dtu_error_t dtu_memory_init(void)
{
    if (g_memory_manager.initialized) {
        return DTU_OK;
    }

    memset(&g_memory_manager, 0, sizeof(memory_manager_t));
    
    if (pthread_mutex_init(&g_memory_manager.mutex, NULL) != 0) {
        return DTU_ERROR;
    }

    g_memory_manager.initialized = true;
    
    DTU_LOG_INFO("Memory manager initialized");
    return DTU_OK;
}

void dtu_memory_cleanup(void)
{
    if (!g_memory_manager.initialized) {
        return;
    }

    pthread_mutex_lock(&g_memory_manager.mutex);

    /* 检查并释放所有未释放的内存 */
    memory_block_t* block = g_memory_manager.blocks;
    while (block) {
        memory_block_t* next = block->next;
        DTU_LOG_WARN("Memory leak detected: %p (%zu bytes) allocated at %s:%d", 
                     block->ptr, block->size, block->file, block->line);
        free(block->ptr);
        free(block);
        block = next;
        g_memory_manager.stats.leak_count++;
    }

    g_memory_manager.blocks = NULL;
    g_memory_manager.initialized = false;

    pthread_mutex_unlock(&g_memory_manager.mutex);
    pthread_mutex_destroy(&g_memory_manager.mutex);

    DTU_LOG_INFO("Memory manager cleanup completed, leaks: %u", 
                 g_memory_manager.stats.leak_count);
}

void* dtu_malloc(size_t size, const char* file, int line)
{
    if (!g_memory_manager.initialized) {
        if (dtu_memory_init() != DTU_OK) {
            return NULL;
        }
    }

    if (size == 0) {
        DTU_LOG_WARN("Attempting to allocate 0 bytes at %s:%d", file, line);
        return NULL;
    }

    void* ptr = malloc(size);
    if (!ptr) {
        DTU_LOG_ERROR("Memory allocation failed: %zu bytes at %s:%d", size, file, line);
        return NULL;
    }

    /* 创建内存块记录 */
    memory_block_t* block = malloc(sizeof(memory_block_t));
    if (!block) {
        free(ptr);
        DTU_LOG_ERROR("Failed to allocate memory block record at %s:%d", file, line);
        return NULL;
    }

    block->ptr = ptr;
    block->size = size;
    block->file = file;
    block->line = line;
    block->alloc_time = time(NULL);
    block->next = NULL;

    pthread_mutex_lock(&g_memory_manager.mutex);

    /* 添加到链表头部 */
    block->next = g_memory_manager.blocks;
    g_memory_manager.blocks = block;

    /* 更新统计信息 */
    g_memory_manager.stats.total_allocated += size;
    g_memory_manager.stats.current_allocated += size;
    g_memory_manager.stats.alloc_count++;

    if (g_memory_manager.stats.current_allocated > g_memory_manager.stats.peak_allocated) {
        g_memory_manager.stats.peak_allocated = g_memory_manager.stats.current_allocated;
    }

    pthread_mutex_unlock(&g_memory_manager.mutex);

    DTU_LOG_DEBUG("Allocated %zu bytes at %p (%s:%d)", size, ptr, file, line);
    return ptr;
}

void dtu_free(void* ptr, const char* file, int line)
{
    if (!ptr) {
        return; /* 静默处理NULL指针 */
    }

    if (!g_memory_manager.initialized) {
        free(ptr);
        return;
    }

    pthread_mutex_lock(&g_memory_manager.mutex);

    /* 查找内存块 */
    memory_block_t* prev = NULL;
    memory_block_t* block = g_memory_manager.blocks;

    while (block) {
        if (block->ptr == ptr) {
            /* 从链表中移除 */
            if (prev) {
                prev->next = block->next;
            } else {
                g_memory_manager.blocks = block->next;
            }

            /* 更新统计信息 */
            g_memory_manager.stats.current_allocated -= block->size;
            g_memory_manager.stats.free_count++;

            DTU_LOG_DEBUG("Freed %zu bytes at %p (%s:%d)", block->size, ptr, file, line);

            free(ptr);
            free(block);

            pthread_mutex_unlock(&g_memory_manager.mutex);
            return;
        }
        prev = block;
        block = block->next;
    }

    pthread_mutex_unlock(&g_memory_manager.mutex);

    /* 如果找不到内存块，可能是重复释放，静默处理 */
    DTU_LOG_DEBUG("Attempting to free untracked pointer %p at %s:%d (possible double free)", ptr, file, line);
}

void* dtu_calloc(size_t count, size_t size, const char* file, int line)
{
    size_t total_size = count * size;
    void* ptr = dtu_malloc(total_size, file, line);
    if (ptr) {
        memset(ptr, 0, total_size);
    }
    return ptr;
}

void* dtu_realloc(void* ptr, size_t size, const char* file, int line)
{
    if (!ptr) {
        return dtu_malloc(size, file, line);
    }

    if (size == 0) {
        dtu_free(ptr, file, line);
        return NULL;
    }

    if (!g_memory_manager.initialized) {
        DTU_LOG_WARN("Memory manager not initialized, using system realloc at %s:%d", file, line);
        return realloc(ptr, size);
    }

    pthread_mutex_lock(&g_memory_manager.mutex);

    /* 查找原内存块 */
    memory_block_t* block = g_memory_manager.blocks;
    while (block) {
        if (block->ptr == ptr) {
            break;
        }
        block = block->next;
    }

    if (!block) {
        pthread_mutex_unlock(&g_memory_manager.mutex);
        DTU_LOG_WARN("Attempting to realloc untracked pointer %p at %s:%d", ptr, file, line);
        return realloc(ptr, size);
    }

    size_t old_size = block->size;
    void* new_ptr = realloc(ptr, size);
    
    if (!new_ptr) {
        pthread_mutex_unlock(&g_memory_manager.mutex);
        DTU_LOG_ERROR("Memory reallocation failed: %zu bytes at %s:%d", size, file, line);
        return NULL;
    }

    /* 更新内存块信息 */
    block->ptr = new_ptr;
    block->size = size;
    block->file = file;
    block->line = line;

    /* 更新统计信息 */
    g_memory_manager.stats.current_allocated = g_memory_manager.stats.current_allocated - old_size + size;
    g_memory_manager.stats.total_allocated += size;

    if (g_memory_manager.stats.current_allocated > g_memory_manager.stats.peak_allocated) {
        g_memory_manager.stats.peak_allocated = g_memory_manager.stats.current_allocated;
    }

    pthread_mutex_unlock(&g_memory_manager.mutex);

    DTU_LOG_DEBUG("Reallocated %p to %p, size %zu->%zu (%s:%d)", 
                  ptr, new_ptr, old_size, size, file, line);
    return new_ptr;
}

dtu_error_t dtu_memory_get_stats(memory_stats_t* stats)
{
    if (!stats) {
        return DTU_ERROR_INVALID_PARAM;
    }

    if (!g_memory_manager.initialized) {
        memset(stats, 0, sizeof(memory_stats_t));
        return DTU_OK;
    }

    pthread_mutex_lock(&g_memory_manager.mutex);
    *stats = g_memory_manager.stats;
    pthread_mutex_unlock(&g_memory_manager.mutex);

    return DTU_OK;
}

uint32_t dtu_memory_check_leaks(void)
{
    if (!g_memory_manager.initialized) {
        return 0;
    }

    pthread_mutex_lock(&g_memory_manager.mutex);
    
    uint32_t leak_count = 0;
    memory_block_t* block = g_memory_manager.blocks;
    
    while (block) {
        leak_count++;
        block = block->next;
    }

    pthread_mutex_unlock(&g_memory_manager.mutex);
    return leak_count;
}

void dtu_memory_print_usage(void)
{
    memory_stats_t stats;
    if (dtu_memory_get_stats(&stats) != DTU_OK) {
        printf("Failed to get memory statistics\n");
        return;
    }

    printf("=== Memory Usage Statistics ===\n");
    printf("Total allocated:   %zu bytes\n", stats.total_allocated);
    printf("Current allocated: %zu bytes\n", stats.current_allocated);
    printf("Peak allocated:    %zu bytes\n", stats.peak_allocated);
    printf("Allocation count:  %u\n", stats.alloc_count);
    printf("Free count:        %u\n", stats.free_count);
    printf("Leak count:        %u\n", stats.leak_count);
    printf("===============================\n");
}

void dtu_memory_print_leaks(void)
{
    if (!g_memory_manager.initialized) {
        printf("Memory manager not initialized\n");
        return;
    }

    pthread_mutex_lock(&g_memory_manager.mutex);

    printf("=== Memory Leak Report ===\n");
    
    memory_block_t* block = g_memory_manager.blocks;
    uint32_t count = 0;
    
    while (block) {
        count++;
        printf("Leak #%u: %p (%zu bytes) allocated at %s:%d (time: %ld)\n",
               count, block->ptr, block->size, block->file, block->line, block->alloc_time);
        block = block->next;
    }

    if (count == 0) {
        printf("No memory leaks detected\n");
    } else {
        printf("Total leaks: %u\n", count);
    }
    
    printf("==========================\n");

    pthread_mutex_unlock(&g_memory_manager.mutex);
}

bool dtu_memory_validate_ptr(void* ptr)
{
    if (!ptr || !g_memory_manager.initialized) {
        return false;
    }

    pthread_mutex_lock(&g_memory_manager.mutex);

    memory_block_t* block = g_memory_manager.blocks;
    while (block) {
        if (block->ptr == ptr) {
            pthread_mutex_unlock(&g_memory_manager.mutex);
            return true;
        }
        block = block->next;
    }

    pthread_mutex_unlock(&g_memory_manager.mutex);
    return false;
}

size_t dtu_memory_get_size(void* ptr)
{
    if (!ptr || !g_memory_manager.initialized) {
        return 0;
    }

    pthread_mutex_lock(&g_memory_manager.mutex);

    memory_block_t* block = g_memory_manager.blocks;
    while (block) {
        if (block->ptr == ptr) {
            size_t size = block->size;
            pthread_mutex_unlock(&g_memory_manager.mutex);
            return size;
        }
        block = block->next;
    }

    pthread_mutex_unlock(&g_memory_manager.mutex);
    return 0;
}
